package com.betting.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.betting.entity.BetRecord;
import com.betting.entity.BetResultStatus;
import com.betting.dto.StreakStats;
import com.betting.dto.StreakDetail;
import com.betting.mapper.BetRecordMapper;
import com.betting.service.BetRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.betting.dto.WeeklyProfitDTO;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.format.DateTimeFormatter;
import java.util.TreeMap;

@Service
@RequiredArgsConstructor
public class BetRecordServiceImpl extends ServiceImpl<BetRecordMapper, BetRecord> implements BetRecordService {
    
    private final BetRecordMapper betRecordMapper;

    @Override
    public Page<BetRecord> getRecordsByPage(Page<BetRecord> page, LambdaQueryWrapper<BetRecord> wrapper) {
        return betRecordMapper.selectPage(page, wrapper);
    }

    @Override
    public BetRecord saveRecord(BetRecord record) {
        // 如果需要，可以在这里进行字符串到BigDecimal的转换
        // record.setHandicapValue(new BigDecimal(record.getHandicapValue()));
        betRecordMapper.insert(record);
        return record;
    }

    @Override
    public boolean updateById(BetRecord record) {
        // 如果需要，可以在这里进行字符串到BigDecimal的转换
        // record.setHandicapValue(new BigDecimal(record.getHandicapValue()));
        return betRecordMapper.updateById(record) > 0;
    }

    @Override
    public void deleteRecord(Long id) {
        betRecordMapper.deleteById(id);
    }

    @Override
    public Map<String, Object> getDailySummary(LocalDate date) {
        LocalDateTime startTime = date.atStartOfDay();
        LocalDateTime endTime = date.atTime(LocalTime.MAX);
        return calculateSummary(startTime, endTime);
    }

    @Override
    public Map<String, Object> getWeeklySummary(LocalDate date) {
        // 处理跨年的情况
        LocalDate startDate = date.minusDays(date.getDayOfWeek().getValue() - 1);
        LocalDate endDate = startDate.plusDays(6);
        return calculateSummary(startDate.atStartOfDay(), endDate.atTime(LocalTime.MAX));
    }

    @Override
    public BetRecord getRecordById(Long id) {
        return betRecordMapper.selectById(id);
    }

    @Override
    public List<BetRecord> getRecordsByDateRange(LocalDate startDate, LocalDate endDate) {
        return betRecordMapper.selectList(
            new LambdaQueryWrapper<BetRecord>()
                .between(BetRecord::getBetTime, 
                        startDate.atStartOfDay(), 
                        endDate.atTime(LocalTime.MAX))
                .orderByDesc(BetRecord::getBetTime)
        );
    }

    @Override
    public Map<String, Object> getStatistics(LocalDate startDate, LocalDate endDate) {
        Map<String, Object> stats = new HashMap<>();
        
        // 查询时间范围内的所有记录
        List<BetRecord> records = lambdaQuery()
                .ge(BetRecord::getBetTime, startDate.atStartOfDay())
                .le(BetRecord::getBetTime, endDate.atTime(LocalTime.MAX))
                .orderByAsc(BetRecord::getBetTime)
                .list();
        
        // 计算基础统计数据
        BigDecimal totalBetAmount = BigDecimal.ZERO;
        BigDecimal totalProfit = BigDecimal.ZERO;
        int totalBetCount = 0;
        Map<String, Integer> resultCounts = new HashMap<>();
        Map<LocalDate, BigDecimal> dailyProfits = new HashMap<>(); // 改用HashMap提高性能
        
        for (BetRecord record : records) {
            // 计算总投注金额
            totalBetAmount = totalBetAmount.add(record.getBetAmount() != null ? 
                record.getBetAmount() : BigDecimal.ZERO);
            
            // 计算总收益和每日收益
            BigDecimal resultAmount = record.getResultAmount() != null ? 
                record.getResultAmount() : BigDecimal.ZERO;
            totalProfit = totalProfit.add(resultAmount);
            
            // 计算每日收益
            LocalDate betDate = record.getBetTime().toLocalDate();
            dailyProfits.merge(betDate, resultAmount, BigDecimal::add);
            
            // 统计结果分布
            String result = record.getBetResult();
            if (result != null && !result.isEmpty()) {
                totalBetCount++;
                resultCounts.merge(result, 1, Integer::sum);
            }
        }
        
        // 计算命中率（考虑半胜权重）
        double winCount = resultCounts.getOrDefault("WIN", 0) 
                       + resultCounts.getOrDefault("HALF_WIN", 0) * 0.5;
        double hitRate = totalBetCount > 0 ? (winCount / totalBetCount) * 100 : 0;
        
        // 准备每日收益数据
        List<String> dailyProfitDates = new ArrayList<>();
        List<BigDecimal> dailyProfitValues = new ArrayList<>();
        dailyProfits.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> {
                dailyProfitDates.add(entry.getKey().format(DateTimeFormatter.ofPattern("MM-dd")));
                dailyProfitValues.add(entry.getValue());
            });
        
        // 准备结果分布数据
        List<Map<String, Object>> resultDistribution = new ArrayList<>();
        String[] resultTypes = {"WIN", "HALF_WIN", "DRAW", "HALF_LOSE", "LOSE"};
        String[] resultNames = {"全胜", "半胜", "平局", "半负", "全负"};
        for (int i = 0; i < resultTypes.length; i++) {
            int count = resultCounts.getOrDefault(resultTypes[i], 0);
            if (count > 0) {
                Map<String, Object> item = new HashMap<>();
                item.put("name", resultNames[i]);
                item.put("value", count);
                resultDistribution.add(item);
            }
        }
        
        // 设置返回数据
        stats.put("totalBetAmount", totalBetAmount);
        stats.put("totalProfit", totalProfit);
        stats.put("totalBetCount", totalBetCount);
        stats.put("hitRate", hitRate);
        stats.put("dailyProfitDates", dailyProfitDates);
        stats.put("dailyProfitValues", dailyProfitValues);
        stats.put("resultDistribution", resultDistribution);
        
        return stats;
    }

    @Override
    public StreakStats getStreakStats(LocalDate startDate, LocalDate endDate) {
        // 构建查询条件
        LambdaQueryWrapper<BetRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.isNotNull(BetRecord::getBetResult)
               .orderByAsc(BetRecord::getBetTime);
        
        // 添加日期范围条件
        if (startDate != null) {
            wrapper.ge(BetRecord::getBetTime, startDate.atStartOfDay());
        }
        if (endDate != null) {
            wrapper.le(BetRecord::getBetTime, endDate.atTime(23, 59, 59));
        }
        
        // 查询记录
        List<BetRecord> records = list(wrapper);
        
        // 计算统计数据
        int maxWinStreak = 0;
        int maxLoseStreak = 0;
        int currentWinStreak = 0;
        int currentLoseStreak = 0;
        int totalBets = 0;
        int winningBets = 0;
        BigDecimal totalResultAmount = BigDecimal.ZERO;
        List<StreakDetail> details = new ArrayList<>();
        BigDecimal runningTotal = BigDecimal.ZERO;
        
        // 一次性遍历计算所有数据
        for (int i = 0; i < records.size(); i++) {
            BetRecord record = records.get(i);
            if (record.getBetResult() != null) {
                try {
                    totalBets++;
                    BigDecimal resultAmount = record.getResultAmount() != null ? 
                        record.getResultAmount() : BigDecimal.ZERO;
                    totalResultAmount = totalResultAmount.add(resultAmount);
                    
                    BetResultStatus betResult = BetResultStatus.fromValue(record.getBetResult());
                    if (betResult == BetResultStatus.WIN || betResult == BetResultStatus.HALF_WIN) {
                        winningBets++;
                        currentWinStreak++;
                        currentLoseStreak = 0;
                        maxWinStreak = Math.max(maxWinStreak, currentWinStreak);
                    } else if (betResult == BetResultStatus.LOSE || betResult == BetResultStatus.HALF_LOSE) {
                        currentLoseStreak++;
                        currentWinStreak = 0;
                        maxLoseStreak = Math.max(maxLoseStreak, currentLoseStreak);
                    }
                    // 和局不改变连胜连败状态
                    
                    String streak;
                    if (betResult == BetResultStatus.DRAW) {
                        streak = "和";
                    } else {
                        streak = currentWinStreak > 0 ? "+" + currentWinStreak :
                                currentLoseStreak > 0 ? "-" + currentLoseStreak : "0";
                    }
                    
                    // 构建比赛信息
                    String homeTeam = record.getHomeTeam() != null ? record.getHomeTeam() : "";
                    String awayTeam = record.getAwayTeam() != null ? record.getAwayTeam() : "";
                    String matchInfo = homeTeam + " vs " + awayTeam;
                    
                    StreakDetail detail = new StreakDetail();
                    detail.setBetTime(record.getBetTime());  // 直接设置 LocalDateTime
                    detail.setMatch(matchInfo);
                    detail.setBetType(record.getBetType());
                    
                    // 设置水位
                    if (record.getOdds() != null) {
                        detail.setOdds(record.getOdds().doubleValue());
                    }
                    
                    // 处理盘口值的转换
                    String handicapStr = record.getHandicapValue();
                    if (handicapStr != null && !handicapStr.trim().isEmpty()) {
                        try {
                            // 尝试转换为数字
                            detail.setHandicapValue(Double.parseDouble(handicapStr.trim()));
                        } catch (NumberFormatException e) {
                            // 如果不是数字，保持原样
                            detail.setHandicapValue(null);
                            detail.setHandicapText(handicapStr.trim());
                        }
                    } else {
                        detail.setHandicapValue(null);
                    }
                    
                    detail.setBetResult(record.getBetResult());
                    detail.setResultAmount(resultAmount.doubleValue());  // BigDecimal 转 Double
                    detail.setStreak(streak);  // 直接设置字符串
                    detail.setTotalResultAmount(runningTotal.add(resultAmount).doubleValue());  // BigDecimal 转 Double
                    
                    details.add(detail);
                    runningTotal = runningTotal.add(resultAmount);
                } catch (IllegalArgumentException e) {
                    // 处理无效的BetResult值
                    continue;
                }
            }
        }
        
        // 计算命中率
        double hitRate = totalBets > 0 ? (double) winningBets / totalBets * 100 : 0;
        
        // 不再进行时间倒序排序，保持正序
        // details.sort((a, b) -> b.getBetTime().compareTo(a.getBetTime()));
        
        StreakStats stats = new StreakStats();
        stats.setMaxWinStreak(maxWinStreak);
        stats.setMaxLoseStreak(maxLoseStreak);
        stats.setHitRate(hitRate);
        stats.setStreakDetails(details);
        
        return stats;
    }

    @Override
    public Map<String, Object> getMonthlySummary(LocalDate startDate, LocalDate endDate) {
        // 处理月份边界情况
        LocalDate adjustedStartDate = startDate.withDayOfMonth(1);
        LocalDate adjustedEndDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
        return calculateSummary(adjustedStartDate.atStartOfDay(), adjustedEndDate.atTime(LocalTime.MAX));
    }

    @Override
    public BigDecimal getMonthlyProfit(LocalDate month) {
        LocalDate start = month.withDayOfMonth(1);
        LocalDate end = month.withDayOfMonth(month.lengthOfMonth());
        return betRecordMapper.selectMonthlyProfit(start.atStartOfDay(), end.atTime(23, 59, 59));
    }

    @Override
    public BigDecimal getDailyProfit(LocalDate date) {
        LocalDateTime start = date.atStartOfDay();
        LocalDateTime end = date.atTime(23, 59, 59);
        return betRecordMapper.selectDailyProfit(start, end);
    }

    @Override
    public List<WeeklyProfitDTO> getWeeklyProfits(LocalDate startDate, LocalDate endDate) {
        List<WeeklyProfitDTO> weeklyProfits = new ArrayList<>();
        
        // 计算每周的起始和结束日期
        LocalDate currentStart = startDate;
        while (!currentStart.isAfter(endDate)) {
            LocalDate weekEnd = currentStart.plusDays(6);
            if (weekEnd.isAfter(endDate)) {
                weekEnd = endDate;
            }
            
            // 计算该周的收益
            BigDecimal weeklyProfit = calculateWeeklyProfit(currentStart, weekEnd);
            
            // 创建DTO对象
            WeeklyProfitDTO dto = WeeklyProfitDTO.builder()
                .weekStart(currentStart)
                .weekEnd(weekEnd)
                .profit(weeklyProfit)
                .build();
            
            weeklyProfits.add(dto);
            currentStart = currentStart.plusWeeks(1);
        }
        
        return weeklyProfits;
    }

    private BigDecimal calculateWeeklyProfit(LocalDate startDate, LocalDate endDate) {
        return betRecordMapper.selectWeeklyProfit(
            startDate.atStartOfDay(),
            endDate.atTime(LocalTime.MAX)
        );
    }

    private Map<String, Object> calculateSummary(LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<BetRecord> wrapper = new LambdaQueryWrapper<BetRecord>()
            .between(BetRecord::getBetTime, startTime, endTime);
        
        List<BetRecord> records = betRecordMapper.selectList(wrapper);
        
        BigDecimal totalBet = BigDecimal.ZERO;
        BigDecimal totalResult = BigDecimal.ZERO;
        double winCount = 0;
        
        for (BetRecord record : records) {
            totalBet = totalBet.add(record.getBetAmount() != null ? 
                record.getBetAmount() : BigDecimal.ZERO);
            totalResult = totalResult.add(record.getResultAmount() != null ? 
                record.getResultAmount() : BigDecimal.ZERO);
            
            if (record.getBetResult() != null) {
                try {
                    BetResultStatus betResult = BetResultStatus.fromValue(record.getBetResult());
                    if (betResult == BetResultStatus.WIN) {
                        winCount += 1.0;
                    } else if (betResult == BetResultStatus.HALF_WIN) {
                        winCount += 0.5;
                    }
                } catch (IllegalArgumentException e) {
                    // 处理无效的BetResult值
                    continue;
                }
            }
        }
        
        Map<String, Object> summary = new HashMap<>();
        summary.put("totalBet", totalBet);
        summary.put("totalResult", totalResult);
        summary.put("totalCount", records.size());
        summary.put("winCount", winCount);
        summary.put("winRate", records.size() > 0 ? (winCount / records.size()) * 100 : 0);
        
        return summary;
    }
} 